package edu.pku.sei.autounit.reflect.jdt;

import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;

import edu.pku.sei.autounit.reflect.Context;
import edu.pku.sei.autounit.reflect.Enum;
import edu.pku.sei.autounit.reflect.Type;
import edu.pku.sei.autounit.reflect.TypeParameter;
import edu.pku.sei.autounit.reflect.java.JavaTypeVariable;
import edu.pku.sei.autounit.reflect.java.JavaWildcardType;
import edu.pku.sei.autounit.reflect.java.TypeFactory;
import edu.pku.sei.autounit.util.Log;

public class JDTTypeFactory extends TypeFactory{
//	public final static String NAME = "[_a-zA-Z][_a-zA-Z\\d]*";
//	public final static String ARRAY = NAME+"(\\[\\])+";
//	public final static String Type = "("+NAME+"\\.)*"+NAME;
//	public final static String WILDCARD = "\\?(.)* ";
	
	public Type getType(String name,IType itype,Context context){
		Type type = map.get(name);
		if(type != null)
			return type;
		
		else if(name.endsWith("[]")){
			int i=0;
			while(name.endsWith("[]")){
				i++;
				name = name.substring(0,name.length()-2);
			}
			return new JDTArray(getType(name,itype,context),i);
		}
		
		else if(name.startsWith("?")){
			Type lower = null;
			Type upper = null;
			int index = name.indexOf("extends");
			if(index != -1){
				String tn = name.substring(index+7);
				upper = getType(tn,itype,context);
			}
			
			index = name.indexOf("super");
			if(index != -1){
				String tn = name.substring(index+5);
				lower = getType(tn,itype,context);
			}
			
			return new JavaWildcardType(lower,upper);
		}
		
		else if(name.endsWith(">")){
			int c = name.indexOf('<');
			String g = name.substring(c+1,name.length()-1);
			String t = name.substring(0,c);
			
			
			List<Type> gt = new ArrayList<Type>();
			for(String gg:g.split(",")){
				gt.add(getType(gg,itype,context));
			}
			try {
				String [][]ss = itype.resolveType(t);
				if(ss == null){
					Log.findBug("TypeFactory", "getType", "can't resolve "+t);
					return null;
				}
				name = ss[0][0]+"."+ss[0][1];
				IType it = itype.getJavaProject().findType(name);
				if(it != null){
					return getType(it,gt.toArray(new Type[0]));
				}
				else{
					Log.findBug("TypeFactory", "getType", "can't find "+name);
					return null;
				}
				
			} catch (JavaModelException e) {
				Log.gotUnexpectedExection("TypeFactory", "getType", "", e);
				return null;
			}
		}
		
		else{
			try {
				String [][]ss = itype.resolveType(name);
				if(ss == null){
					if(context==null)
						return new JavaTypeVariable(name,new Type[0]);
					TypeParameter p = context.getTypeParameter(name);
					if(p == null)
						return new JavaTypeVariable(name,new Type[0]);
					else if(p.getContext()!=null)
						return p.getContext();
					else
						return new JavaTypeVariable(name,p.getBounds());
				}
				name = ss[0][0]+"."+ss[0][1];
				IType it = itype.getJavaProject().findType(name);
				if(it != null){
					type = getType(it);
					if(type instanceof Enum)
						map.put(name, type);
					else if(type instanceof Context){
						if(((Context) type).getContexts().length==0)
							map.put(name, type);
					}
					return type;
				}
				else{
					Log.findBug("TypeFactory", "getType", "can't find "+name);
					return null;
				}
			} catch (JavaModelException e) {
				Log.gotUnexpectedExection("TypeFactory", "getType", "", e);
				return null;
			}
		}	
	}
	
	public Type getType(IType type){
		try {
			if(type.isEnum())
				return new JDTEnum(type);
			else if(type.isClass())
				return new JDTClass(type,this);
			else if(type.isInterface())
				return new JDTInterface(type,this);
		} catch (JavaModelException e) {
			Log.gotUnexpectedExection("TypeFactory", "getType", "", e);
		}
		Log.findBug("TypeFactory", "getType"," can't deal with "+type);
		return null;
	}
	
	public Type getType(IType type,Type []contexts){
		try {
			if(type.isClass())
				return new JDTClass(type,contexts,this);
			else if(type.isInterface())
				return new JDTInterface(type,contexts,this);
		} catch (JavaModelException e) {
			Log.gotUnexpectedExection("TypeFactory", "getType", "", e);
		}
		Log.findBug("TypeFactory", "getType"," can't deal with "+type);
		return null;
	}
}
